// 
// GroupEditDialog.cs
// 
// Copyright © 2008, 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
//
// GroupEditDialog.cs is part of SpiderIM.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//


using System;
using System.Collections.Generic;
using Gtk;
using Glade;
using Galaxium.Protocol.Xmpp.Library;
using Galaxium.Protocol.Xmpp.Library.Utility;

namespace Galaxium.Protocol.Xmpp.GtkGui
{
	// TODO: Clean this up a bit....
	public class GroupEditDialog
	{
		[Widget] Dialog   dialog          = null;
		[Widget] Entry    new_group_entry = null;
		[Widget] Button   add_button      = null;
		[Widget] TreeView group_view      = null;

		Contact[] m_contacts;
				
		public static void Open (Window parent, Contact[] contacts)
		{
			var dialog = new GroupEditDialog (parent, contacts);
			dialog.Run ();
		}
		
		private GroupEditDialog (Window parent, Contact[] contacts)
		{
			var gxml = new Glade.XML (null, "GroupEditDialog.glade", null, null);
			gxml.Autoconnect (this);
			
			m_contacts = contacts;
			var model = new ListStore (typeof (string), typeof (bool),
			                           typeof (bool), typeof (bool));
			group_view.Model = model;
			group_view.Selection.Mode = SelectionMode.Single;

			group_view.RowActivated += (a, b) => OnRowToggle ();
			
			foreach (string group in contacts [0].Client.Roster.Groups) {
				if (String.IsNullOrEmpty (group)) continue;
				var iter = model.Append ();
				model.SetValue (iter, 0, group);

				bool active = contacts [0].Groups.Contains (group);
				bool inconsistent = true;

				foreach (var contact in contacts) {
					if (inconsistent) { inconsistent = false; continue; } // skip first
					if (active == contact.Groups.Contains (group)) continue;
					inconsistent = true; break;
				}
				
				model.SetValue (iter, 1, active);
				model.SetValue (iter, 2, inconsistent);
				model.SetValue (iter, 3, inconsistent);
			}

			var col = new TreeViewColumn ("Groups", new CellRendererText (), "markup", 0);
			col.Expand = true;
			group_view.AppendColumn (col);
			group_view.AppendColumn (String.Empty, new CellRendererToggle (),
			                         "active", 1, "inconsistent", 2);
			
			(model as TreeSortable).DefaultSortFunc = (m, a, b) => {
				return String.Compare ((m.GetValue (a, 0) as String).ToLower (),
				                       (m.GetValue (b, 0) as String).ToLower ());
			};
			(model as TreeSortable).SetSortColumnId (-1, SortType.Ascending);

			add_button.Clicked += OnAddButtonClick;
		}

		private void Run ()
		{
			if (dialog.Run () == 1)
				SetGroups ();

			dialog.Destroy ();
		}

		private void OnRowToggle ()
		{
			TreeModel nic;
			TreeIter iter;
			if (!group_view.Selection.GetSelected (out nic, out iter)) return;

			bool active = (bool) group_view.Model.GetValue (iter, 1);
			bool inconsistent = (bool) group_view.Model.GetValue (iter, 2);
			bool was_inconsistent = (bool) group_view.Model.GetValue (iter, 3);
				
			if (!inconsistent) active = !active;
			inconsistent = !inconsistent && active && was_inconsistent;

			group_view.Model.SetValue (iter, 1, active);
			group_view.Model.SetValue (iter, 2, inconsistent);
		}
		
		private void OnAddButtonClick (object o, EventArgs args)
		{
			if (new_group_entry.Text == String.Empty) return;
			TreeIter iter = (group_view.Model as ListStore).Append ();
			group_view.Model.SetValue (iter, 0, new_group_entry.Text);
			group_view.Model.SetValue (iter, 1, true);
			group_view.Model.SetValue (iter, 2, false);
			group_view.Model.SetValue (iter, 3, false);
			new_group_entry.Text = String.Empty;
		}

		private void SetGroups ()
		{
			var active = new List<string> ();
			var inconsistent = new List<string> ();

			group_view.Model.Foreach ((TreeModel model, TreePath path, TreeIter iter) => {
				string group = (string) model.GetValue (iter, 0);
				if ((bool) model.GetValue (iter, 2))
					inconsistent.Add (group);
				else if ((bool) model.GetValue (iter, 1))
					active.Add (group);
				return false;
			});

			foreach (var contact in m_contacts) {
				var groups = new List<string> (active);
				foreach (string group in inconsistent)
					if (contact.Groups.Contains (group)) groups.Add (group);
				contact.Client.Roster.RequestContactGroupsChange (contact, groups);
			}
		}
	}
}
